home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / class.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  13KB  |  533 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.  * This is free software distributed under the terms of the
  3.  * GNU Public License.  See the file COPYING for details.
  4.  *
  5.  * $Id: class.c,v 1.18 2001/02/15 08:39:45 drscholl Exp $
  6.  *
  7.  * Based on bans.c in part.
  8.  * oracle ip database idea taken from ircd
  9.  * is_address() taken from hybrid ircd and modified to return a complete
  10.  * ip.
  11.  * All this mess put together by Colten Edwards (q)
  12.  */
  13.  
  14. /* Modified 30/05/01 : Added include "extrasocket.h" with inlines for a few
  15.       for Amiga port : bsdsocket.library functions not emulated by ixemul
  16.  
  17.                        Added define for htonl(), which is not defined in the
  18.                        Amiga GCC 2.7.0 includes
  19. */
  20.  
  21. #define htonl(x) (x)
  22.  
  23. #include <ctype.h>
  24. #include <string.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <errno.h>
  28. #include <limits.h>
  29. #include <sys/types.h>
  30. #include <sys/socket.h>
  31. #include <netinet/in.h>
  32. #include <arpa/inet.h>
  33. #include <unistd.h>
  34. #include "opennap.h"
  35. #include "hashlist.h"
  36. #include "debug.h"
  37.  
  38. #include "extrasocket.h"
  39.  
  40. #define F_SYNC (1<<0)
  41.  
  42. typedef struct
  43. {
  44.     char   *name;
  45.     LIST   *list;
  46.     unsigned int flags;
  47.     unsigned int oracle[256];
  48. }
  49. acl_t;
  50.  
  51. static acl_t ilines;
  52. static acl_t dlines;
  53. static acl_t elines;
  54. static acl_t limits;
  55.  
  56. #define check_oracle(acl,ip)    (((acl)->oracle[(ip) & 0xff] & (ip)) == (ip))
  57.  
  58. int
  59. check_class (CONNECTION * con, ip_info_t * info)
  60. {
  61.     LIST   *list;
  62.     CLASS  *class;
  63.     int     count, boot_em = 0;
  64.  
  65.     count = info->users;
  66.  
  67.     if (!count)
  68.         return count;
  69.  
  70.     if (Max_Clones > 0 && count >= Max_Clones)
  71.         boot_em = count;
  72.  
  73.     if (check_oracle (&limits, con->ip))
  74.     {
  75.         for (list = limits.list; list; list = list->next)
  76.         {
  77.             class = list->data;
  78.             if ((con->ip & class->mask) == (class->target & class->mask))
  79.             {
  80.                 if (count >= class->limit)
  81.                     return count;
  82.                 else
  83.                     return 0;
  84.             }
  85.         }
  86.     }
  87.     return boot_em;
  88. }
  89.  
  90. /* determine whether a connection from this ip address is allowed by the acls
  91.  * defined.
  92.  */
  93. int
  94. acl_connection_allowed (unsigned int ip)
  95. {
  96.     if (ilines.list)
  97.     {
  98.         /* i:lines exist, don't allow any connections unless the ip
  99.          * matches
  100.          */
  101.         if (!check_oracle (&ilines, ip))
  102.             return 0;
  103.     }
  104.  
  105.     /* check for a d:line */
  106.     if (check_oracle (&dlines, ip))
  107.     {
  108.         /* check for an e:line */
  109.         if (check_oracle (&elines, ip))
  110.             return 1;
  111.  
  112.         return 0;
  113.     }
  114.  
  115.     return 1;
  116. }
  117.  
  118. static int
  119. generic_acl_save (acl_t * acl)
  120. {
  121.     FILE   *fp;
  122.     LIST   *list;
  123.     access_t *b;
  124.     char    path[_POSIX_PATH_MAX];
  125.     char    maskstr[sizeof ("/xxx.xxx.xxx.xxx")];
  126.  
  127.     snprintf (path, sizeof (path), "%s/%s", Config_Dir, acl->name);
  128.  
  129.     if (acl->list == 0)
  130.     {
  131.         unlink (path);
  132.         return 0;
  133.     }
  134.  
  135. #ifdef WIN32
  136. #define LE "\r\n"
  137. #else
  138. #define LE "\n"
  139. #endif
  140.  
  141.     if ((fp = fopen (path, "w")) == 0)
  142.         return -1;
  143.     fprintf (fp,
  144.              "# DO NOT EDIT THIS FILE! - automatically generated by opennap%s",
  145.              LE);
  146.     fprintf (fp, "# Hi Mom, We got %s!%s", acl->name, LE);
  147.     for (list = acl->list; list; list = list->next)
  148.     {
  149.         struct in_addr in;
  150.  
  151.         b = list->data;
  152.         maskstr[0] = 0;
  153.         if (b->mask != 0xffffffff)
  154.         {
  155.             in.s_addr = BSWAP32 (b->mask);
  156.             snprintf (maskstr, sizeof (maskstr), "/%s", inet_ntoa (in));
  157.         }
  158.         in.s_addr = BSWAP32 (b->ip);
  159.         fprintf (fp, "%s%s %3d%s", inet_ntoa (in), maskstr, b->count, LE);
  160.     }
  161.     if (fclose (fp))
  162.     {
  163.         logerr ("generic_acl_save", "fclose");
  164.         return -1;
  165.     }
  166.     return 0;
  167. }
  168.  
  169. void
  170. acl_save (void)
  171. {
  172.     generic_acl_save (&limits);
  173.     generic_acl_save (&ilines);
  174.     generic_acl_save (&dlines);
  175.     generic_acl_save (&elines);
  176. }
  177.  
  178. static int
  179. compare_ipmask (unsigned int a, unsigned int amask, unsigned int b,
  180.                 unsigned int bmask)
  181. {
  182.     int     r = -2;
  183.  
  184.     /* always use the smallest mask to compare */
  185.     unsigned int usemask = (amask > bmask) ? bmask : amask;
  186.  
  187.     /*
  188.        struct in_addr in;
  189.        in.s_addr = ntohl(a);
  190.        printf("comparing %s(%u) and", inet_ntoa(in), a);
  191.        in.s_addr = ntohl(b);
  192.        printf(" %s(%u) = ",inet_ntoa(in), b);
  193.        in.s_addr = ntohl(usemask);
  194.        printf(" using mask=%s  ", inet_ntoa(in));
  195.      */
  196.  
  197.     if ((a & usemask) == (b & usemask))
  198.     {
  199.         /*printf("masks are equal  "); */
  200.         /* the larger mask (more specific) should sort first */
  201.         if (bmask != amask)
  202.             r = (amask > bmask) ? 1 : -1;
  203.     }
  204.  
  205.     /* otherwise sort by ip */
  206.     if (r == -2)
  207.     {
  208.         if (b == a)
  209.             r = 0;
  210.         else
  211.             r = (b > a) ? 1 : -1;
  212.     }
  213.  
  214.     /*
  215.        printf("%d\n", r);
  216.      */
  217.  
  218.     return r;
  219. }
  220.  
  221. /** acl_insert
  222.  * @param acl   access list to modify
  223.  * @param ipstr ip/mask string
  224.  * @param nstr  limit to place on class
  225.  * @returns -1 on error, 0 if new acl was added, 1 if existing acl was changed
  226.  */
  227. static int
  228. acl_insert (acl_t * acl, char *ipstr, int count)
  229. {
  230.     unsigned int ip, mask;
  231.     LIST  **access_list = &acl->list;
  232.     access_t *acc;
  233.     LIST   *list;
  234.     int     r;
  235.  
  236.     if (!is_address (ipstr, &ip, &mask))
  237.         return -1;
  238.  
  239.     for (; *access_list; access_list = &(*access_list)->next)
  240.     {
  241.         acc = (*access_list)->data;
  242.         r = compare_ipmask (htonl (BSWAP32 (ip)), htonl (BSWAP32 (mask)),
  243.                             htonl (BSWAP32 (acc->ip)),
  244.                             htonl (BSWAP32 (acc->mask)));
  245.         if (r == 0)
  246.         {
  247.             acc->count = count;
  248.             return 1;
  249.         }
  250.         else if (r > 0)
  251.             break;
  252.     }
  253.     acc = CALLOC (1, sizeof (access_t));
  254.     if (!acc)
  255.     {
  256.         OUTOFMEMORY ("acl_insert");
  257.         return -1;
  258.     }
  259.     acc->ip = ip;
  260.     acc->mask = mask;
  261.     acc->count = count;
  262.     list = CALLOC (1, sizeof (LIST));
  263.     if (!list)
  264.     {
  265.         FREE (acc);
  266.         OUTOFMEMORY ("acl_insert");
  267.         return -1;
  268.     }
  269.     list->next = *access_list;
  270.     *access_list = list;
  271.     list->data = acc;
  272.     acl->oracle[ip & 0xff] |= (ip | ~mask);
  273.     return 0;
  274. }
  275.  
  276. static int
  277. generic_acl_load (acl_t * acl)
  278. {
  279.     FILE   *fp;
  280.     int     ac;
  281.     char   *av[2], *ptr, path[_POSIX_PATH_MAX];
  282.     int     line = 0;
  283.  
  284.     snprintf (path, sizeof (path), "%s/%s", Config_Dir, acl->name);
  285.  
  286.     if (!(fp = fopen (path, "r")))
  287.     {
  288.         if (errno != ENOENT)
  289.             logerr ("generic_acl_load", path);
  290.         return -1;
  291.     }
  292.     while (fgets (Buf, sizeof (Buf) - 1, fp))
  293.     {
  294.         line++;
  295.         ptr = Buf;
  296.         while (ISSPACE (*ptr))
  297.             ptr++;
  298.         if (*ptr == '#' || *ptr == 0)
  299.             continue;
  300.         ac = split_line (av, FIELDS (av), Buf);
  301.         if (ac < 1)
  302.             continue;
  303.  
  304.         if (acl_insert (acl, av[0], (ac > 1) ? atoi (av[1]) : 0) == -1)
  305.         {
  306.             log ("generic_acl_load:%s:%d:error parsing line:%s %s",
  307.                  path, line, av[0], (ac > 1) ? av[1] : "");
  308.         }
  309.     }
  310.     fclose (fp);
  311.     return 0;
  312. }
  313.  
  314. static acl_t *
  315. get_acl (int tag)
  316. {
  317.     if (tag == MSG_CLIENT_DLINE_ADD || tag == MSG_CLIENT_DLINE_DEL
  318.         || tag == MSG_CLIENT_DLINE_LIST)
  319.         return &dlines;
  320.     if (tag == MSG_CLIENT_ELINE_ADD || tag == MSG_CLIENT_ELINE_DEL
  321.         || tag == MSG_CLIENT_ELINE_LIST)
  322.         return &elines;
  323.     if (tag == MSG_CLIENT_ILINE_ADD || tag == MSG_CLIENT_ILINE_DEL
  324.         || tag == MSG_CLIENT_ILINE_LIST)
  325.         return &ilines;
  326.     if (tag == MSG_CLIENT_CLASS_ADD || tag == MSG_CLIENT_CLASS_DEL
  327.         || tag == MSG_CLIENT_CLASS_LIST)
  328.         return &limits;
  329.     return 0;
  330. }
  331.  
  332. static void
  333. generic_acl_init (acl_t * acl, const char *name, int flags)
  334. {
  335.     memset (acl, 0, sizeof (acl));
  336.     acl->name = STRDUP (name);
  337.     acl->flags = flags;
  338. }
  339.  
  340. void
  341. acl_init (void)
  342. {
  343.     generic_acl_init (&limits, "limit", F_SYNC);
  344.     generic_acl_load (&limits);
  345.     generic_acl_init (&ilines, "iline", 0);
  346.     generic_acl_load (&ilines);
  347.     generic_acl_init (&dlines, "dline", 0);
  348.     generic_acl_load (&dlines);
  349.     generic_acl_init (&elines, "eline", 0);
  350.     generic_acl_load (&elines);
  351. }
  352.  
  353. /* ??? [:sender] <host>[/<mask>] [arg]
  354.  */
  355. HANDLER (generic_acl_add)
  356. {
  357.     int     ac;
  358.     char   *av[2];
  359.     char   *sender_name;
  360.     USER   *sender;
  361.     acl_t  *acl;
  362.     int     count, modified = 0;
  363.  
  364.     (void) len;
  365.     if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
  366.         return;
  367.     if (sender && sender->level < LEVEL_MODERATOR)
  368.         return;
  369.  
  370.     ac = split_line (av, FIELDS (av), pkt);
  371.     if (ac < 1)
  372.         return;
  373.  
  374.     acl = get_acl (tag);
  375.     count = (ac > 1) ? atoi (av[1]) : 0;
  376.     modified = acl_insert (acl, av[0], count);
  377.     if (modified == -1)
  378.     {
  379.         if (ISUSER (con))
  380.             send_cmd (con, MSG_SERVER_NOSUCH, "unable to parse ip/mask");
  381.         return;
  382.     }
  383.     notify_mods (CHANGELOG_MODE, "%s%s %s %s on %s (%d)",
  384.                  sender ? "" : "Server ",
  385.                  sender_name,
  386.                  modified ? "modified" : "added", acl->name, av[0], count);
  387.  
  388.     if (acl->flags & F_SYNC)
  389.         pass_message_args (con, tag, ":%s %s %d", sender_name, av[0], count);
  390.  
  391.     generic_acl_save (acl);
  392. }
  393.  
  394. /* ??? [:sender] <host>[/<mask>] */
  395. HANDLER (generic_acl_del)
  396. {
  397.     char   *host;
  398.     unsigned int ip, mask;
  399.     LIST  **access_list;
  400.     LIST   *tmp;
  401.     char   *sender_name;
  402.     USER   *sender;
  403.     access_t *acc;
  404.     acl_t  *acl;
  405.  
  406.     (void) len;
  407.     if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
  408.         return;
  409.     if (sender && sender->level < LEVEL_MODERATOR)
  410.         return;
  411.     host = next_arg (&pkt);
  412.     if (!host)
  413.         return;
  414.     if (!is_address (host, &ip, &mask))
  415.         return;
  416.     acl = get_acl (tag);
  417.     access_list = &acl->list;
  418.  
  419.     if (!check_oracle (acl, ip))
  420.     {
  421.         if (ISUSER (con))
  422.             send_cmd (con, MSG_SERVER_NOSUCH, "no matching ip addresses");
  423.         return;
  424.     }
  425.  
  426.     for (; *access_list; access_list = &(*access_list)->next)
  427.     {
  428.         acc = (*access_list)->data;
  429.         if (mask == acc->mask && (ip & mask) == (acc->ip & acc->mask))
  430.         {
  431.             tmp = *access_list;
  432.             *access_list = (*access_list)->next;
  433.             FREE (tmp);
  434.             break;
  435.         }
  436.     }
  437.  
  438.     /* rebuild the oracle */
  439.     memset (acl->oracle, 0, sizeof (int) * 256);
  440.  
  441.     for (tmp = acl->list; tmp; tmp = tmp->next)
  442.     {
  443.         acc = tmp->data;
  444.         acl->oracle[acc->ip & 0xff] |= (acc->ip | ~acc->mask);
  445.     }
  446.  
  447.     notify_mods (CHANGELOG_MODE, "%s%s removed %s on %s",
  448.                  sender ? "" : "Server ", sender_name, acl->name, host);
  449.  
  450.     if (acl->flags & F_SYNC)
  451.         pass_message_args (con, tag, ":%s %s", sender_name, host);
  452.  
  453.     generic_acl_save (acl);
  454. }
  455.  
  456. /* ??? */
  457. HANDLER (generic_acl_list)
  458. {
  459.     access_t *acc;
  460.     acl_t  *acl;
  461.     char    maskstr[sizeof ("/xxx.xxx.xxx.xxx")];
  462.     struct in_addr in;
  463.     LIST   *list;
  464.  
  465.     (void) len;
  466.     (void) pkt;
  467.     CHECK_USER_CLASS ("generic_acl_list");
  468.     if (con->user->level < LEVEL_MODERATOR)
  469.         return;
  470.     acl = get_acl (tag);
  471.     for (list = acl->list; list; list = list->next)
  472.     {
  473.         acc = list->data;
  474.  
  475.         maskstr[0] = 0;
  476.         if (acc->mask != 0xffffffff)
  477.         {
  478.             in.s_addr = BSWAP32 (acc->mask);
  479.             snprintf (maskstr, sizeof (maskstr), "/%s", inet_ntoa (in));
  480.         }
  481.  
  482.         in.s_addr = BSWAP32 (acc->ip);
  483.         send_cmd (con, tag, "%s%s %d", inet_ntoa (in), maskstr, acc->count);
  484.     }
  485.     send_cmd (con, tag, "");
  486. }
  487.  
  488. static void
  489. generic_acl_sync (CONNECTION * con, int tag, acl_t * acl)
  490. {
  491.     LIST   *list;
  492.     access_t *c;
  493.     struct in_addr in;
  494.     char    maskstr[sizeof ("/xxx.xxx.xxx.xxx")];
  495.  
  496.     ASSERT (validate_connection (con));
  497.     for (list = acl->list; list; list = list->next)
  498.     {
  499.         c = list->data;
  500.         maskstr[0] = 0;
  501.         if (c->mask != 0xffffffff)
  502.         {
  503.             in.s_addr = BSWAP32 (c->mask);
  504.             snprintf (maskstr, sizeof (maskstr), "/%s", inet_ntoa (in));
  505.         }
  506.         in.s_addr = BSWAP32 (c->ip);
  507.         send_cmd (con, tag, ":%s %s%s %d", Server_Name,
  508.                   inet_ntoa (in), maskstr, c->count);
  509.     }
  510. }
  511.  
  512. void
  513. acl_sync (CONNECTION * con)
  514. {
  515.     generic_acl_sync (con, MSG_CLIENT_CLASS_ADD, &limits);
  516. }
  517.  
  518. static void
  519. acl_free (acl_t * acl)
  520. {
  521.     list_free (acl->list, free_pointer);
  522.     FREE (acl->name);
  523. }
  524.  
  525. void
  526. acl_destroy (void)
  527. {
  528.     acl_free (&limits);
  529.     acl_free (&dlines);
  530.     acl_free (&ilines);
  531.     acl_free (&elines);
  532. }
  533.